﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;
using ScrumLite.Services.Contracts;
using System.Globalization;

namespace ScrumLite.Services.Tests
{
    [TestClass]
    public class LinqDeliverableServiceFixture
    {
        MockRepository mocks;

        Guid projectId = Guid.NewGuid();
        Guid idDeliverable = Guid.NewGuid();
        Guid idWorkArea = Guid.NewGuid();
        Guid idDeliverableWorkArea = Guid.NewGuid();

        ScrumLite.Data.WorkArea expectedWorkArea;
        ScrumLite.Data.Deliverable expectedDeliverable;
        System.Data.Linq.EntitySet<ScrumLite.Data.DeliverableWorkArea> deliverablesWorkAreas;
        int expectedMoniker = 1;

        [TestInitialize]
        public void Initialize()
        {
            this.mocks = new MockRepository();
            // a workarea
            expectedWorkArea = new ScrumLite.Data.WorkArea
            {
                fk_project = projectId,
                name = "WorkArea1",
                id = idWorkArea,
            };

            // a workarea deliverable
            deliverablesWorkAreas = new System.Data.Linq.EntitySet<ScrumLite.Data.DeliverableWorkArea>();
            deliverablesWorkAreas.Add(new ScrumLite.Data.DeliverableWorkArea()
            {
                id = idDeliverableWorkArea,
                pk_deliverable = idDeliverable,
                WorkArea = expectedWorkArea
            });

            // a deliverable
            expectedDeliverable = new ScrumLite.Data.Deliverable
              {
                  id = idDeliverable,
                  uri_repository = "http://www.projectrepository.com/",
                  releasedOn = DateTime.Now,
                  fileName = "FileName1",
                  moniker = 1,
                  pk_project = projectId,
                  DeliverableWorkAreas = deliverablesWorkAreas
              };

        }

        [TestMethod]
        public void ShouldGetADeliverable()
        {
            ScrumLite.Data.IDeliverableStore store = this.mocks.DynamicMock<ScrumLite.Data.IDeliverableStore>();

            ScrumLite.Data.Deliverable expected = new ScrumLite.Data.Deliverable() { id = idDeliverable, fileName = "fileName", moniker = 1, pk_project = projectId, releasedOn = DateTime.Now, uri_repository = "http://project.com" };

            // set an expectation that will do a callback and set the argument 
            // to a local member to perform Asserts later
            Expect.Call(store.GetDeliverable(idDeliverable))
                .Return(expected)
                .Callback(new Func<Guid, bool>(g => { return true; }));
            mocks.ReplayAll();

            LinqDeliverablesService service = new LinqDeliverablesService(store);

            Deliverable actual = service.GetDeliverable(idDeliverable.ToString());

            Assert.IsNotNull(actual);
            Assert.AreEqual(expected.id, actual.Id);
            Assert.AreEqual(expected.fileName, actual.Name);
        }

        [TestMethod]
        public void ShouldGetDeliverables()
        {
            ScrumLite.Data.IDeliverableStore store = mocks.DynamicMock<ScrumLite.Data.IDeliverableStore>();

            List<ScrumLite.Data.Deliverable> expectedDeliverables = new List<ScrumLite.Data.Deliverable>();
            expectedDeliverables.Add(expectedDeliverable);
            ScrumLite.Data.Deliverable[] expected = expectedDeliverables.ToArray();

            // set an expectation that will do a callback and set the argument 
            // to a local member to perform Asserts later
            Expect.Call(store.GetDeliverables(idDeliverable.ToString()))
                .Return(expected)
                .Callback(new Func<string, bool>(g => { return true; }));
            mocks.ReplayAll();

            LinqDeliverablesService service = new LinqDeliverablesService(store);

            Deliverable[] deliverables = service.GetDeliverables(projectId.ToString());

            Assert.AreEqual(deliverables.Length, 1, "Array incompleto.");
            Assert.AreEqual(expected[0].id, deliverables[0].Id);
            Assert.AreEqual(expected[0].fileName, deliverables[0].Name);
            Assert.AreEqual(deliverables.Length, 1);
            Assert.AreEqual(expected[0].moniker, deliverables[0].Moniker);
            Assert.AreEqual(expected[0].releasedOn, deliverables[0].ReleasedOn);            

        }

        [TestMethod]
        public void ShouldGetWorkAreas()
        {
            ScrumLite.Data.IDeliverableStore store = mocks.DynamicMock<ScrumLite.Data.IDeliverableStore>();

            ScrumLite.Data.WorkArea expectedWA = new ScrumLite.Data.WorkArea() {  id = Guid.NewGuid(), name = "TestName" };

            List<ScrumLite.Data.WorkArea> expectedWorkAreas = new List<ScrumLite.Data.WorkArea>();
            expectedWorkAreas.Add(expectedWA);
            ScrumLite.Data.WorkArea[] expected = expectedWorkAreas.ToArray();
            Guid deliverableId = Guid.NewGuid();

            // set an expectation that will do a callback and set the argument 
            // to a local member to perform Asserts later
            Expect.Call(store.GetWorkAreas(deliverableId))
                .Return(expected)
                .Callback(new Func<Guid, bool>(g => { return true; }));
            mocks.ReplayAll();

            LinqDeliverablesService service = new LinqDeliverablesService(store);

            WorkArea[] workAreas = service.GetWorkAreas(deliverableId.ToString());

            Assert.AreEqual(workAreas.Length, 1, "Array incompleto.");
            Assert.AreEqual(expected[0].id.ToString(), workAreas[0].Id);
            Assert.AreEqual(expected[0].name, workAreas[0].Name);
        }

        [TestMethod]
        public void ShouldGetDeliverablesByWorkArea()
        {
            ScrumLite.Data.IDeliverableStore store = mocks.DynamicMock<ScrumLite.Data.IDeliverableStore>();

            List<ScrumLite.Data.Deliverable> expectedDeliverables = new List<ScrumLite.Data.Deliverable>();
            expectedDeliverables.Add(expectedDeliverable);
            ScrumLite.Data.Deliverable[] expected = expectedDeliverables.ToArray();

            // set an expectation that will do a callback and set the argument 
            // to a local member to perform Asserts later
            Expect.Call(store.GetDeliverablesByWorkArea(expectedWorkArea))
                .Return(expected)
                .Callback(new Func<ScrumLite.Data.WorkArea, bool>(g => { return true; }));
            mocks.ReplayAll();

            LinqDeliverablesService service = new LinqDeliverablesService(store);


            ScrumLite.Services.Contracts.WorkArea workArea = new WorkArea() { Id = idDeliverableWorkArea.ToString(), Name = expectedWorkArea.name };
            Deliverable[] actualDeliverables = service.GetDeliverablesByWorkArea(workArea);

            Assert.AreEqual(actualDeliverables.Length, 1, "Array incompleto.");
            Assert.AreEqual(expected[0].id, actualDeliverables[0].Id);
            Assert.AreEqual(expected[0].fileName, actualDeliverables[0].Name);
            Assert.AreEqual(actualDeliverables.Length, 1);
            Assert.AreEqual(expected[0].moniker, actualDeliverables[0].Moniker);
            Assert.AreEqual(expected[0].releasedOn, actualDeliverables[0].ReleasedOn);

            //check workAreas
            Assert.AreEqual(expectedWorkArea.name, actualDeliverables[0].WorkAreas[0].Name);
            Assert.AreEqual(expectedWorkArea.id.ToString(), actualDeliverables[0].WorkAreas[0].Id);

        }
        
        [TestMethod]
        public void ShouldGetDeliverablesByMoniker()
        {
            ScrumLite.Data.IDeliverableStore store = mocks.DynamicMock<ScrumLite.Data.IDeliverableStore>();

            List<ScrumLite.Data.Deliverable> expectedDeliverables = new List<ScrumLite.Data.Deliverable>();
            expectedDeliverables.Add(expectedDeliverable);

            //set an expectation that will do a callback and set the argument 
            //to a local member to perform Asserts later
            Expect.Call(store.GetDeliverableByMoniker(projectId.ToString(), expectedMoniker))
                .Return(expectedDeliverable.id)
                .Callback(new Func<string, int, bool>((g, e) => { return true; }));
            mocks.ReplayAll();

            //TODO: Check

            LinqDeliverablesService service = new LinqDeliverablesService(store);
            Guid actualGuid = service.GetDeliverableByMoniker(projectId.ToString(), expectedMoniker);

            Assert.AreEqual(expectedDeliverable.id, actualGuid);
        }

        [TestMethod]
        public void ShouldAddDeliverable()
        {
            ScrumLite.Data.IDeliverableStore store = mocks.DynamicMock<ScrumLite.Data.IDeliverableStore>();

            List<ScrumLite.Data.Deliverable> actual = new List<ScrumLite.Data.Deliverable>();

            // set an expectation that will do a callback and set the argument 
            // to a local member to perform Asserts later
            Expect.Call(() => store.Add(null))
                .Callback(new Func<ScrumLite.Data.Deliverable, bool>(r => { actual.Add(r); return true; }))
                .Repeat.Times(2);
            mocks.ReplayAll();

            LinqDeliverablesService service = new LinqDeliverablesService(store);

            List<ScrumLite.Services.Contracts.WorkArea> workAreas = new List<WorkArea>() { new WorkArea() { Id = expectedWorkArea.id.ToString(), Name = expectedWorkArea.name }};

            ScrumLite.Services.Contracts.Deliverable deliverable = new Deliverable()
            {
                Id = expectedDeliverable.id,
                Moniker = expectedDeliverable.moniker,
                Name = expectedDeliverable.fileName,
                ReleasedOn = expectedDeliverable.releasedOn,
                Url = new Uri(expectedDeliverable.uri_repository),
                WorkAreas = workAreas.ToArray()
            };

            service.Add(projectId.ToString(), deliverable);

            Assert.AreEqual(actual.Count, 1);
            
            Assert.AreEqual(expectedDeliverable.moniker, actual[0].moniker);
            Assert.AreEqual(expectedDeliverable.releasedOn, actual[0].releasedOn);
            Assert.AreEqual(expectedDeliverable.uri_repository, actual[0].uri_repository);
            Assert.AreEqual(expectedDeliverable.fileName, actual[0].fileName);

            //Check WorkArea            
            Assert.AreEqual(expectedWorkArea.id, actual[0].DeliverableWorkAreas[0].pk_workarea);
            
        }

        [TestMethod]
        public void ShouldUpdateDeliverable()
        {
            ScrumLite.Data.IDeliverableStore store = mocks.DynamicMock<ScrumLite.Data.IDeliverableStore>();

            ScrumLite.Data.Deliverable actual = null;

            // set an expectation that will do a callback and set the argument 
            // to a local member to perform Asserts later
            Expect.Call(() => store.Update(null))
                .Callback(new Func<ScrumLite.Data.Deliverable, bool>(d => { actual = d; return true; }));
            mocks.ReplayAll();

            LinqDeliverablesService service = new LinqDeliverablesService(store);

            List<ScrumLite.Services.Contracts.WorkArea> workAreas = new List<WorkArea>() { new WorkArea() { Id = expectedWorkArea.id.ToString(), Name = expectedWorkArea.name } };

            ScrumLite.Services.Contracts.Deliverable deliverable = new Deliverable()
            {
                Id = expectedDeliverable.id,
                Moniker = expectedDeliverable.moniker,
                Name = expectedDeliverable.fileName,
                ReleasedOn = expectedDeliverable.releasedOn,
                Url = new Uri(expectedDeliverable.uri_repository),
                WorkAreas = workAreas.ToArray()
            };

            service.Update(projectId.ToString(), deliverable);

            Assert.IsNotNull(actual);
            Assert.AreEqual(expectedDeliverable.id, actual.id);
            Assert.AreEqual(expectedDeliverable.moniker, actual.moniker);
            Assert.AreEqual(expectedDeliverable.releasedOn, actual.releasedOn);
            Assert.AreEqual(expectedDeliverable.uri_repository, actual.uri_repository);
            Assert.AreEqual(expectedDeliverable.fileName, actual.fileName);

            //Check WorkArea            
            Assert.AreEqual(expectedWorkArea.id, actual.DeliverableWorkAreas[0].pk_workarea);

        }
    }
}
